package com.xspace.android.xafcommon.location;

import android.util.SparseArray;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.xspace.android.xafcommon.appliction.BaseApplication;
import com.xspace.android.xafcommon.util.LogUtil;

/**
 * Wubj 创建于 2017/4/6.
 */
public class MyAMapLocation implements AMapLocationListener {

    private static MyAMapLocation location;

    public static LocationInfoBean resultLocation;
    private AMapLocationClient locationClient;
    private LocationResult mLocationResult;

    public final static SparseArray<String> errorCode = new SparseArray<>();

    public static MyAMapLocation getInstance() {
        if (location == null) {
            location = new MyAMapLocation();
        }
        return location;
    }

    private MyAMapLocation() {
        //初始化定位
        initLocation();
    }

    /**
     * 初始化定位
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    private void initLocation() {
        //初始化client
        locationClient = new AMapLocationClient(BaseApplication.mInstance);
        //设置定位参数
        locationClient.setLocationOption(getDefaultOption());
        // 设置定位监听
        locationClient.setLocationListener(this);
    }

    /**
     * 默认的定位参数
     *
     * @since 2.8.0
     */
    private AMapLocationClientOption getDefaultOption() {
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        //可选，设置定位模式，可选的模式有高精度、仅设备、仅网络。默认为高精度模式
        mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
        mOption.setGpsFirst(false);//可选，设置是否gps优先，只在高精度模式下有效。默认关闭
        mOption.setHttpTimeOut(30000);//可选，设置网络请求超时时间。默认为30秒。在仅设备模式下无效
        mOption.setInterval(10 * 1000);//可选，设置定位间隔。默认为2秒
        mOption.setNeedAddress(true);//可选，设置是否返回逆地理地址信息。默认是true
        mOption.setOnceLocation(false);//可选，设置是否单次定位。默认是false
        mOption.setOnceLocationLatest(false);//可选，设置是否等待wifi刷新，默认为false.如果设置为true,会自动变为单次定位，持续定位时不要使用
        //可选，设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
//        AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);
        mOption.setSensorEnable(false);//可选，设置是否使用传感器。默认是false
        mOption.setWifiScan(true); //可选，设置是否开启wifi扫描。默认为true，如果设置为false会同时停止主动刷新，停止以后完全依赖于系统刷新，定位位置可能存在误差
        mOption.setLocationCacheEnable(true); //可选，设置是否使用缓存定位，默认为true
        return mOption;
    }

    /**
     * 开始定位
     *
     * @since 2.8.0
     */
    public void startLocation() {
        stopLocation();
        // 启动定位
        locationClient.startLocation();
    }

    /**
     * 停止定位
     *
     * @since 2.8.0
     */
    private void stopLocation() {
        if (locationClient.isStarted()) {
            // 停止定位
            locationClient.stopLocation();
        }
    }

    public void relocation(LocationResult locationResult) {
        if (!locationClient.isStarted()) {
            locationClient.startLocation();
        }
        mLocationResult = locationResult;
    }

    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {
        setResultLocation(aMapLocation);
    }

    private void setResultLocation(AMapLocation aMapLocation) {
        if (null == aMapLocation) {
            if (mLocationResult != null) {
                mLocationResult.locationErr("定位失败");
                mLocationResult = null;
            }
        } else if (aMapLocation.getErrorCode() == 0) {
            //errCode等于0代表定位成功，其他的为定位失败，具体的可以参照官网定位错误码说明
            LocationInfoBean bean = new LocationInfoBean();
            bean.errorCode = aMapLocation.getErrorCode();
            bean.locationType = aMapLocation.getLocationType();
            bean.longitude = aMapLocation.getLongitude();
            bean.latitude = aMapLocation.getLatitude();
            bean.accuracy = aMapLocation.getAccuracy();
            bean.provider = aMapLocation.getProvider();
            bean.speed = aMapLocation.getSpeed();
            bean.bearing = aMapLocation.getBearing();
            bean.satellites = aMapLocation.getSatellites();
            bean.country = aMapLocation.getCountry();
            bean.province = aMapLocation.getProvince();
            bean.city = aMapLocation.getCity();
            bean.cityCode = aMapLocation.getCityCode();
            bean.district = aMapLocation.getDistrict();
            bean.adCode = aMapLocation.getAdCode();
            bean.address = aMapLocation.getAddress();
            bean.poiName = aMapLocation.getPoiName();
            bean.time = aMapLocation.getTime();
            bean.successTime = System.currentTimeMillis();
            if (mLocationResult != null) {
                mLocationResult.result(true, bean);
                mLocationResult = null;
            }
            resultLocation = bean;
            LogUtil.e("接收到位置信息:locationType: " + bean.locationType + " address:" + bean.address);
        } else {
            if (mLocationResult != null) {
                mLocationResult.locationErr(errorCode.get(aMapLocation.getErrorCode()));
                mLocationResult = null;
            }
        }
    }

    static {
        /*
         0
         定位成功。
         可以在定位回调里判断定位返回成功后再进行业务逻辑运算。
         1
         一些重要参数为空，如context；
         请对定位传递的参数进行非空判断。
         2
         定位失败，由于仅扫描到单个wifi，且没有基站信息。
         请重新尝试。
         3
         获取到的请求参数为空，可能获取过程中出现异常。
         请对所连接网络进行全面检查，请求可能被篡改。
         4
         请求服务器过程中的异常，多为网络情况差，链路不通导致
         请检查设备网络是否通畅，检查通过接口设置的网络访问超时时间，建议采用默认的30秒。
         5
         请求被恶意劫持，定位结果解析失败。
         您可以稍后再试，或检查网络链路是否存在异常。
         6
         定位服务返回定位失败。
         请获取errorDetail（通过getLocationDetail()方法获取）信息并参考定位常见问题进行解决。
         7
         KEY鉴权失败。
         请仔细检查key绑定的sha1值与apk签名sha1值是否对应，或通过高频问题查找相关解决办法。
         8
         Android exception常规错误
         请将errordetail（通过getLocationDetail()方法获取）信息通过工单系统反馈给我们。
         9
         定位初始化时出现异常。
         请重新启动定位。
         10
         定位客户端启动失败。
         请检查AndroidManifest.xml文件是否配置了APSService定位服务
         11
         定位时的基站信息错误。
         请检查是否安装SIM卡，设备很有可能连入了伪基站网络。
         12
         缺少定位权限。
         请在设备的设置中开启app的定位权限。
         13
         定位失败，由于设备未开启WIFI模块或未插入SIM卡，且GPS当前不可用。
         建议开启设备的WIFI模块，并将设备中插入一张可以正常工作的SIM卡，或者检查GPS是否开启；如果以上都内容都确认无误，请您检查App是否被授予定位权限。
         14
         GPS 定位失败，由于设备当前 GPS 状态差。
         建议持设备到相对开阔的露天场所再次尝试。
         15
         定位结果被模拟导致定位失败
         如果您希望位置被模拟，请通过setMockEnable(true);方法开启允许位置模拟
         16
         当前POI检索条件、行政区划检索条件下，无可用地理围栏
         建议调整检索条件后重新尝试，例如调整POI关键字，调整POI类型，调整周边搜区域，调整行政区关键字等。
         */

        errorCode.put(1, "参数异常，一些重要参数为空");
        errorCode.put(2, "定位失败，尝试重新请求定位");
        errorCode.put(3, "获取到的请求参数为空，可能获取过程中出现异常");
        errorCode.put(4, "网络连接异常，请检查设备网络是否通畅");
        errorCode.put(5, "请求被恶意劫持，定位结果解析失败");
        errorCode.put(6, "定位服务返回定位失败");
        errorCode.put(7, "KEY鉴权失败");
        errorCode.put(8, "系统错误");
        errorCode.put(9, "定位初始化时出现异常，请重新启动定位");
        errorCode.put(10, "定位客户端启动失败");
        errorCode.put(11, "定位时的基站信息错误，请检查是否安装SIM卡");
        errorCode.put(12, "缺少定位权限，请在设备的设置中开启app的定位权限");
        errorCode.put(13, "定位失败，由于设备未开启WIFI模块或未插入SIM卡，且GPS当前不可用");
        errorCode.put(14, "GPS 定位失败，由于设备当前 GPS 状态差");
        errorCode.put(15, "定位结果被模拟导致定位失败");
        errorCode.put(16, "当前POI检索条件、行政区划检索条件下，无可用地理围栏");
    }
}
